package com.iisigroup.project.statistics;

import java.io.File; 
import java.io.IOException; 
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map; 
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

 

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileUtils; 
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;   
import org.reflections.Reflections;
import org.reflections.scanners.ResourcesScanner;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import org.reflections.util.FilterBuilder; 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 

import com.iisigroup.project.statistics.job.JobStatCommonBase;
import com.iisigroup.project.statistics.model.Function;

public class ScanMC extends ScanBase{
    /** The Constant logger. */
    private static final Logger LOGGER = LoggerFactory.getLogger(ScanMC.class);
    private String TW_GOV_MOI_EXPR="tw.gov.moi.*";
    private String CONTROLLER_EXPR=".*Controller";
    private String CONTROLLER_SUFFIX="Controller";
    
    private String mcsrcApiLocation ="/opt/ramdisk/work/workspaces/eclipse_38/MC/sris-mc-api/src/main/java";
    private String mcsrcCoreLocation ="/opt/ramdisk/work/workspaces/eclipse_38/MC/sris-mc-core/src/main/java";
    private String mcsrcWebLocation ="/opt/ramdisk/work/workspaces/eclipse_38/MC/sris-mc-web/src/main/java";
    private final String pageRootPath = "/opt/ramdisk/work/workspaces/eclipse_38/MC/sris-mc-web/src/main/webapp";
    
      static protected String mcJspLocation="/opt/ramdisk/work/workspaces/eclipse_38/MC/sris-mc-web/src/main/webapp/pages/func";
    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {
	method001(args);
    }
   public static void method001(String[] args) throws IOException{
	final ScanMC ss = new ScanMC();
	final Map<String, Function> data = ss.scanRL();
	final StringBuffer sbf = new StringBuffer();
	final List<String> codeTAskList = new ArrayList<String>(data.keySet());
	Collections.sort(codeTAskList);
	for (String name : codeTAskList) {
	    Function value = data.get(name);
	    sbf.append(value.getFunctionChtName() + "/" + name + "---------------").append("\r");
	    sbf.append("Table Name: " + value.getDisplayTableName()).append("\r");
	    sbf.append("Dto Name: " + value.getDisplayDtoName()).append("\r");
	    sbf.append("Controller Name: " + StringUtils.join(value.getControllerNames(), ",")).append("\r");
	    sbf.append("Controller 所使用的程式/元件,AE元件名稱: " + value.getDisplayControllerUsedCompoenent()).append("\r");
	    sbf.append("Service Name: " + StringUtils.join(value.getServiceNames(), ",")).append("\r");
	    sbf.append("ftl Name: " + value.getDisplayFtlsName()).append("\r");
	    sbf.append("Service 所使用的程式/元件,AE元件名稱: " + value.getDisplayServiceUsedCompoenent()).append("\r");
	    // value.getDisplayDtoName();
	}
	for (String name : codeTAskList) {
	    Function value = data.get(name);
	    System.out.println(value.getDisplayDtoName()); 
	}
	try {
	    outputFile(new File("/home/weblogic/Desktop/Output"), sbf.toString());
	} catch (IOException e) {
	    LOGGER.error(e.getMessage() ,e );
	}
	try {
	    exportReport(data, "/home/weblogic/Desktop/MC_output.xls");
	} catch (Exception e) {
	     LOGGER.error(e.getMessage() ,e );
	}
   }
   
    private final String regexTxId = "TX[\\w1-9]L[\\w1-9]L[0-9]{2}(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])\\d+";
    private final String regexDto = "TX[\\w1-9]L[\\w1-9]L[0-9]{2}(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])\\d+"; 
    
    
  
    public Map<String,Function>  scanRL() throws IOException {
	List<ClassLoader> classLoadersList = new LinkedList<ClassLoader>();
	classLoadersList.add(ClasspathHelper.contextClassLoader());
	classLoadersList.add(ClasspathHelper.staticClassLoader());
	 
	final   Pattern regexControllerName = Pattern.compile( ".*Controller"  );
	final   Pattern regexServiceImplName = Pattern.compile( ".*ServiceImpl"  );
	final   Pattern regexObnfComponentImplName = Pattern.compile( ".*ObnfComponentImpl"  );
	
	final ConfigurationBuilder builder = new ConfigurationBuilder().setScanners(new SubTypesScanner(false ), new ResourcesScanner())
	.setUrls(ClasspathHelper.forClassLoader(classLoadersList.toArray(new ClassLoader[0])))
	.filterInputsBy(
		new FilterBuilder().include(FilterBuilder.prefix ("tw.gov.moi.mc")).excludePackage("tw.gov.moi.ae").excludePackage("tw.gov.moi.domain")
			.excludePackage("tw.gov.moi.security").excludePackage("javax.servlet").excludePackage("tw.gov.moi.dao") );
	
	final Reflections reflections = new Reflections(builder);
	
	final Set<Class<? extends Object>> allClassesSet = reflections.getSubTypesOf(Object.class);
	final Map<String, String> chtCode = geChtNameMap();
	final Map<String,Function> mapData =new HashMap<String,Function> ();
	
	FileScanModules aFileScanModules = new FileScanModules();
	aFileScanModules.setFtls();
	final Map<String, List<File>> funcNameFileListmap = aFileScanModules.arrayByFunName(mcJspLocation);	
	for(final Class<? extends Object> unitClass : allClassesSet){	    
	    final String simpleName = unitClass.getSimpleName();
	    final String canonicalName = unitClass.getCanonicalName();
	    final Matcher controllerMatcher = regexControllerName.matcher(simpleName);
	    final Matcher serviceMatcher = regexServiceImplName.matcher(simpleName);
	    final Matcher obnfComponentMatcher = regexObnfComponentImplName.matcher(simpleName);
	    if(controllerMatcher.matches()){
		 
		final List<String> importedClassNameList =new ArrayList<String>();
		try {
		    final  Set<String> importedClasses = getClassByteByClassType(unitClass);
		    for(final String importedClass  : importedClasses){
			if(importedClass.matches(TW_GOV_MOI_EXPR) && !StringUtils.equalsIgnoreCase(canonicalName, importedClass)){
			    importedClassNameList.add(importedClass);
			}
		    }
		} catch (IOException e) {
		     LOGGER.error(e.getMessage() ,e );
		}		
		final String functionName =StringUtils.remove(simpleName, "Controller").toUpperCase();
		Function function =mapData.get(functionName);
		
		if(function ==null ){
		    function=new Function();
		}		
		function.setFunctionName(functionName.toUpperCase());
		function.setFunctionChtName(chtCode.get(functionName.toUpperCase()));
		final String[] controllerNames = function.getControllerNames();
		if(ArrayUtils.isNotEmpty(controllerNames)){
		    final String[] newControllerNames =  (String[]) ArrayUtils.add(controllerNames, simpleName);
		    function.setControllerNames(newControllerNames);
		}else{
		    function.setControllerNames(new String[]{simpleName});
		}
		 
		function.setControllerImportedClassNames(importedClassNameList.toArray(new String[]{}));
		final	Set<String> rscdset = aFileScanModules.extractRSCDsFromSrc(mcsrcWebLocation, unitClass);
		function.getRscdSet().addAll(rscdset);
		mapData.put(functionName, function);
	    }else  if(serviceMatcher.matches()){ 
		final List<String> importedClassNameList = new ArrayList<String>();
                try {
                    final  Set<String> importedClasses = getClassByteByClassType(unitClass);
                    for (final String importedClass : importedClasses) {
                        if (importedClass.matches(TW_GOV_MOI_EXPR)
                                && !StringUtils.equalsIgnoreCase(canonicalName,
                                        importedClass)) {
                            importedClassNameList.add(importedClass);
                        }
                    }
                } catch (IOException e) {
                     LOGGER.error(e.getMessage() ,e );
                }
		final String functionName =StringUtils.remove(simpleName, "ServiceImpl").toUpperCase();
		Function function =mapData.get(functionName);
		if(function ==null ){
		    function=new Function();
		}		
		function.setFunctionName(functionName.toUpperCase());
		function.setFunctionChtName(chtCode.get(functionName.toUpperCase()));
		final String[] serviceNames = function.getServiceImportedClassNames();
		
		if(ArrayUtils.isNotEmpty(serviceNames)){
		    final String[] newServiceNames =  (String[]) ArrayUtils.add(serviceNames, simpleName);
		    function.setServiceNames (newServiceNames);
		}else{
		    function.setServiceNames(new String[]{simpleName});
		} 
		function.setServiceImportedClassNames(importedClassNameList.toArray(new String[]{}));
		
		final Class<?>[] serviceInterfaces = unitClass.getInterfaces();
		function.setServiceInterfaces(serviceInterfaces);
		
		 
		
		//處理implemented class上的記事例代碼,RSCD代碼 
		final 	List<String> ftls = aFileScanModules.extractFtlsFromJavaSrc(mcsrcCoreLocation, unitClass);
		if(CollectionUtils.isNotEmpty(ftls)){
		    final String[] funcFtls = function.getFtls();
		    if(ArrayUtils.isNotEmpty(funcFtls)){
			final String[] tmpArray = (String[]) ArrayUtils.addAll(funcFtls, ftls.toArray(new String[]{}));
			
			function.setFtls(tmpArray);			
		    }else{
			 function.setFtls(ftls.toArray(new  String[]{}));	
		    }
		   	    
		}
		
		final	Set<String> rscdset = aFileScanModules.extractRSCDsFromSrc(mcsrcCoreLocation, unitClass);
		function.getRscdSet().addAll(rscdset);
		mapData.put(functionName, function);
	    }else  if(obnfComponentMatcher.matches()){
		
		final List<String> importedClassNameList =new ArrayList<String>();
		try {
		    final  Set<String> importedClasses = getClassByteByClassType(unitClass);
		    for(final String importedClass  : importedClasses){
			if(importedClass.matches(TW_GOV_MOI_EXPR) && !StringUtils.equalsIgnoreCase(canonicalName, importedClass)){
			    importedClassNameList.add(importedClass);
			}
		    }
		} catch (IOException e) {
		     LOGGER.error(e.getMessage() ,e );
		}
		final String functionName =StringUtils.remove(simpleName, "ObnfComponentImpl").toUpperCase();
		Function function =mapData.get(functionName);
		if(function ==null ){
		    function=new Function();
		}		
		function.setFunctionName(functionName.toUpperCase());
		function.setFunctionChtName(chtCode.get(functionName.toUpperCase()));
//		final String[] obnfComponentImportedClass = function.getObnfComponentImportedClassNames();
		
		function.setObnfImplementedClass(simpleName);
		function.setObnfComponentImportedClassNames(importedClassNameList.toArray(new String[]{}));
		final	Set<String> rscdset = aFileScanModules.extractRSCDsFromSrc(mcsrcCoreLocation, unitClass);
		function.getRscdSet().addAll(rscdset);
		mapData.put(functionName, function);
	    }
	    final String clazzSimpleName = unitClass.getSimpleName();
	    if (unitClass.isInterface() && StringUtils.contains(clazzSimpleName,  "Service")) {
		
		// 處理interface上面存放記事例代碼
		final List<String> ftls = aFileScanModules.extractFtlsFromJavaSrc(mcsrcApiLocation, unitClass);
		// 處理interface上面存放RSCD代碼
		final Set<String> rscdset = aFileScanModules.extractRSCDsFromSrc(mcsrcApiLocation, unitClass);
		
		final String functionName = StringUtils.remove(clazzSimpleName, "Service").toUpperCase();
		Function function = mapData.get(functionName);
		if (function == null) {
		    function = new Function();
		}
		final String[] ftlArray = function.getFtls();
		if(ArrayUtils.isNotEmpty(ftlArray)){
		    ftls.addAll(Arrays.asList(ftlArray));
		    final Set<String> ftlSet = new HashSet<String>(ftls);
		    final List<String>  newList = new ArrayList<String>(ftlSet);
		    Collections.sort(newList);
		    function.setFtls(newList.toArray(new String[]{}));
		    
		}else{
		    function.setFtls(ftls.toArray(new String[]{}));
		}
		
		Set<String> funcRscdset = function.getRscdSet();
		
		if(funcRscdset!=null){
		    funcRscdset.addAll(rscdset);
		    function.setRscdSet(funcRscdset);
		}else{
		    function.setRscdSet(rscdset);
		}
		mapData.put(functionName, function);
	    }
	    final Function func = JobStatCommonBase.extractJobInfo(unitClass);
            if( func != null ){
                mapData.put(func.getFunctionName(), func);
            }
	}
	
	for(String funName: mapData.keySet()){
	    final    Function func = mapData.get(funName);
	    final  List<File> jspFiles = funcNameFileListmap.get(funName);

	    if(jspFiles!=null){
		
		final Set<String> jspFileNameSet = new HashSet<String>();
		for (File jspFile : jspFiles) {
		    jspFileNameSet.add(jspFile.getName());		    
		}
		for (File jspFile : jspFiles) {
		    File ouputFile = aFileScanModules.getFileFromParsingFile(jspFile,pageRootPath);		    
		    if(ouputFile!=null){
			if (!jspFileNameSet.contains(ouputFile.getName())) {
			    func.getJspFileList().add(ouputFile);
			    jspFileNameSet.add( ouputFile.getName());
			}
		    }
		}
		List<File> immediateJspFiles = func.getJspFileList();
		List<File> immediate3rdJspFiles = new ArrayList<File>();
		for (File jspFile : immediateJspFiles) {
		    File ouputFile = aFileScanModules.getFileFromParsingFile(jspFile,pageRootPath);		    
		    if(ouputFile!=null){
			if (!jspFileNameSet.contains(ouputFile.getName())) {
			    immediate3rdJspFiles.add(ouputFile);
			}
		    }
		}
		func.getJspFileList().addAll(jspFiles);
		func.getJspFileList().addAll(immediate3rdJspFiles);
		
		Set<String> controllerSet = aFileScanModules.extractControllerNameFormFiles(func.getJspFileList());
		func.setReallyUsedControllerNames(controllerSet);
		//將引用外部的Controller找出
		
		final	Set<String> rscdSet = aFileScanModules.extractRSCDFromjspFiles(func.getJspFileList());
		func.getRscdSet().addAll(rscdSet);
	    }
	   
	    
	}
   	System.out.println("extractSample size: " + mapData.values().size());
	System.out.println("extractSample end..");
	
	return mapData;
    }
    
    
  private Map<String, String> geChtNameMap() { 
	return geChtNameMap("MCCDTKLST.properties");
  }

     
}
